// 角色相关操作API接口实现

#include "ApiHandle.h"

#include <mysql++/connection.h>
#include <mysql++/transaction.h>
#include <mysql++/query.h>
#include <rapidjson/writer.h>

#include <cpptools/out.h>
#include <cpptools/stringutil.h>
#include <cpptools/stdstring.hpp>

#include "node.h"
#include "main.h"
#include "PubOpt.pb.h"
#include "PubProtocol.h"

static constexpr const uint64_t kInfo = ct::Out::flagValue({ (uint64_t)out::kApiRoleInfo });
static constexpr const uint64_t kErr = ct::Out::flagValue({ (uint64_t)out::kApiRoleErr });

// 列表
void ApiHandle::roleList(uptr_t&& uptr) {
    rapidjson::Document::MemberIterator it;
    int page, pageSize;

    // Step: 必要参数
    if ((it = doc.FindMember("token")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Role list, token.\n");
        return sendHead(pub::err::kParams);
    }

    uint64_t token = it->value.GetUint64();
    doc.RemoveMember(it);

    if ((it = doc.FindMember("page")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType
        || (page = it->value.GetInt()) < 1) {
        ct::Out::debug("Error --> Role list, page.\n");
        return sendHead(pub::err::kParams);
    }
    doc.RemoveMember(it);

    if ((it = doc.FindMember("pageSize")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType
        || (pageSize = it->value.GetInt()) < 1) {
        ct::Out::debug("Error --> Role list, pageSize.\n");
        return sendHead(pub::err::kParams);
    }
    doc.RemoveMember(it);

    // Step: 校验权限
    auto tokenOpt = Token::find(token);
    if (!tokenOpt) {
        return sendHead(pub::err::kToken);
    }
    auto& accSptr = (*tokenOpt)->accountSptr();
    if (!accSptr->pmsExist(Main::kPmsNameRoleRead)) {
        return sendHead(pub::err::kPermission);
    }

    // Step: 从map中取到vector中
    std::vector<Role*> valid; // 单线程调度,存指针不会出现计数为0情况.
    
    // keyword可选查询条件
    if ((it = doc.FindMember("keyword")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kStringType) {
        const char* keyword = it->value.GetString();
        
        if (accSptr->sys() & protect::kAllRole) { // 所有角色帐号
            for (auto& itr : Role::all) {
                if (itr.second->name().find(keyword) != std::string::npos) { // 名字包括指定内容即匹配
                    valid.push_back(itr.second);
                }
            }
        } else { // 普通帐号
            for (auto& itr : accSptr->role()) {
                if (itr->name().find(keyword) != std::string::npos) { // 名字包括指定内容即匹配
                    valid.push_back(itr);
                }
            }
        }

    } else {
        if (accSptr->sys() & protect::kAllRole) { // 所有角色帐号
            for (auto& itr : Role::all) {
                valid.push_back(itr.second);
            }
        } else { // 普通帐号
            for (auto& itr : accSptr->role()) {
                valid.push_back(itr);
            }
        }
    }

    // Step: 排序，自定义比较函数
    /*std::sort(valid.begin(), valid.end(), 
              [](const Role* node1, const Role* node2) -> int { 
                  return (node1->id() < node2->id());
              }
            );*/

    // Step: 构造JSON并发送
    int total = (size_t)valid.size();
    int i = total - 1 - (page - 1) * pageSize; // 定位到指定的记录数
    int insNums = 0;
    if (i >= total) { i = i % total; }

    setHead((uint8_t)pub::err::kSuccess); // 协议头
    rapidjson::Writer<buffer_t> w(buf);

    w.StartObject();
    w.Key("total");
    w.Int(total);
    w.Key("list");
    w.StartArray();

    while (i >= 0 && insNums < pageSize) {
        w.StartObject();

        w.Key("id");
        w.Uint(valid[i]->id());
        w.Key("protect");
        w.Uint(valid[i]->sys());
        w.Key("name");
        w.String(valid[i]->name().data(), (rapidjson::SizeType)valid[i]->name().size());

        insNums++; // 已加入的记录数
        i--;
        w.EndObject();
    }

    w.EndArray();
    w.EndObject();

    session->sendReponse(std::move(buf));
}

void ApiHandle::roleDetail(uptr_t&& uptr) {
    struct Info : public InfoBase {
        using InfoBase::InfoBase;
        Account::sptr_t accSptr;
        uint32_t id;
    };
    
    rapidjson::Document::MemberIterator it;

    // Step: 必要参数校验
    if ((it = doc.FindMember("token")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Role detail, token.\n");
        return sendHead(pub::err::kParams);
    }
    auto tokenOpt = Token::find(it->value.GetUint64());
    if (!tokenOpt) {
        return sendHead(pub::err::kToken);
    }
    doc.RemoveMember(it);
    auto& accSptr = (*tokenOpt)->accountSptr();

    if ((it = doc.FindMember("id")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Role detail, id.\n");
        return sendHead(pub::err::kParams);
    }

    auto p = std::make_unique<Info>(std::forward<uptr_t>(uptr));
    p->id = it->value.GetUint();
    
    // Step: 校验权限
    if (!accSptr->pmsExist(Main::kPmsNameRoleRead)) {
        return sendHead(pub::err::kPermission);
    }

    //p->req = std::move(req);
    
    p->accSptr = accSptr;

    // Step：查数据库
    auto funcDb = [p = std::move(p)] () mutable {
        // 任务线程执行代码开始
        char buf[1024];
        
        enum Idx {
            NAME,
            CREATE_TIME,
            UPDATE_TIME,
            CREATE_ACCOUNT,
            DESCRIBE,
        };
        
        int len = sprintf(buf, "select `name`,`createTime`,`updateTime`,`createAccount`,`describe` "\
                      "from `%s` where `id`='%u';", Main::kTableNameRole, p->id);
        ct::Out::debug("sql:%s.\n", buf);

        auto db = Main::dbpool->grab();
        auto query = db->query();
        auto res = query.store(buf, len);

        if (!res) { // 数据库读取错误
            ct::Out::flag(kErr, "Error --> Role detail, err(%d)(%s), sql(%s).\n", 
                          query.errnum(), query.error(), buf);
            return Main::post([p = std::move(p)] { p->api->sendHead(pub::err::kInternal); });
        }

        if (res.num_rows() == 0) { // 没有记录
            ct::Out::flag(kInfo, "Error --> Role detail nodata: sql(%s).\n", buf);
            return Main::post([p = std::move(p)] { p->api->sendHead(pub::err::kNotFound); });
        }

        // 读取成功, 只会有一条记录, 需要处理权限, 放到主线程处理
        auto funcMain = [p = std::move(p), row = std::move(res[0])] {
            auto& api= p->api;
            auto roleNode = Role::find(p->id); // 

            if (!roleNode) {
                return api->sendHead(pub::err::kPermission);
            }

            auto& accSptr = p->accSptr;
            uint32_t sys = roleNode->sys();
            rapidjson::Writer<buffer_t> w(api->buf);
            api->setHead((uint8_t)pub::err::kSuccess); // 协议头

            w.StartObject();
            w.Key("name");
            w.String(row[NAME].data(), (rapidjson::SizeType)row[NAME].size());
            w.Key("describe");
            w.String(row[DESCRIBE].data(), (rapidjson::SizeType)row[DESCRIBE].size());
            w.Key("protect");
            w.Uint(sys);
            w.Key("createAccount");
            w.String(row[CREATE_ACCOUNT].data(), (rapidjson::SizeType)row[CREATE_ACCOUNT].size());
            w.Key("createTime");
            w.String(row[CREATE_TIME].data(), (rapidjson::SizeType)row[CREATE_TIME].size());
            w.Key("updateTime");
            w.String(row[UPDATE_TIME].data(), (rapidjson::SizeType)row[UPDATE_TIME].size());
            
            // 权限处理,根据当前帐号权限组合，只展示当前帐号拥有的权限
            w.Key("pms");
            w.StartArray();

            pms_list_t targetRolePms; // 目标角色权限列表
            roleNode->pmsAll(targetRolePms);

            pms_list_t thisAccPms; // 本帐号权限列表存储指针(单线程没问题,后面要排序追求效率)
            accSptr->pmsAll(thisAccPms);

            // 两个列表比较
            for (auto& itr : thisAccPms) {
                //outDebug("Pms(%p), id:%u, name:%s.\n", itr, itr->id(), itr->name().data());
                w.StartObject();
                w.Key("id");
                w.Uint(itr->id());
                w.Key("alias");
                w.String(itr->alias().c_str(), (rapidjson::SizeType)itr->alias().size());
                w.Key("set");
                w.Int(targetRolePms.find(itr) == targetRolePms.end() ? 0 : 1); // 查找在目标列表中是否存在
                w.EndObject();
            }

            w.EndArray(); // pms array
            w.EndObject();
            api->session->sendReponse(std::move(api->buf));
        };

        Main::post(std::move(funcMain)); // 推到主线程处理发送
    };

    // 新线程中处理数据库操作
    Main::tpool->push(std::move(funcDb)); // 线程池中处理
}

void ApiHandle::roleCreate(uptr_t&& uptr) {
    struct Info : public InfoBase {
        using InfoBase::InfoBase;
        ct::StdString pmsStr; // 权限字符串形式 [1,2,3]
        string_t name, describe;
        Account::sptr_t accSptr;
        pms_list_t pms; // 权限列表
        std::vector<uint32_t> thisCurrentRoleIds; // 当前创建帐号目前的角色列表(更新本帐号db时使用)
        bool thisUpdateDatabase { false }; // 修改本帐号数据库中角色列表(非全角色帐号新加角色号自动为本帐号添加此角色)
        uint32_t newId; // 新创建的角色ID
    };
    
    rapidjson::Document::MemberIterator it;
    auto p = std::make_unique<Info>(std::forward<uptr_t>(uptr));

    // Step: 必要参数
    if ((it = doc.FindMember("token")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Role create, token.\n");
        return sendHead(pub::err::kParams); // token
    }
    uint64_t token = it->value.GetUint64();
    doc.RemoveMember(it);
    size_t len;

    if ((it = doc.FindMember("name")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kStringType
        || (len = it->value.GetStringLength()) > Role::kNameMaxLen || len < 1) { // 名称
        ct::Out::debug("Error --> Role create, name.\n");
        return sendHead(pub::err::kParams);
    }
    p->name.assign(it->value.GetString(), len);
    doc.RemoveMember(it);

    // Step: 校验权限
    auto tokenOpt = Token::find(token);
    if (!tokenOpt) {
        return sendHead(pub::err::kToken);
    }
    auto& accSptr = (*tokenOpt)->accountSptr();

    if (!accSptr->pmsExist(Main::kPmsNameRoleWrite)) {
        return sendHead(pub::err::kPermission);
    }

    // Step: 可选参数
    if ((it = doc.FindMember("describe")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kStringType) {
        if ((len = it->value.GetStringLength()) > Role::kDescMaxLen) {
            ct::Out::debug("Error --> Role create, describe len.\n");
            return sendHead(pub::err::kParams);
        }
        p->describe.assign(it->value.GetString(), len);
        doc.RemoveMember(it);
    }

    if ((it = doc.FindMember("pms")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kArrayType) {
        auto array = it->value.GetArray();
        p->pmsStr.reserve(array.Size() * 2);
        rapidjson::Writer<ct::StdString> w(p->pmsStr);
        w.StartArray();
        for (auto& id : array) {
            if (id.GetType() != rapidjson::kNumberType) {
                continue;
            }
            auto pmsNode = Permission::find(id.GetUint()); // 全局权限列表查找是否有此权限
            if (pmsNode && accSptr->pmsExistProtect(pmsNode)) { // 本帐号有此权限
                if (p->pms.insert(pmsNode).second) { // 防止有重复的传入ID, set有过滤功能, 加入成功才处理
                    w.Uint(id.GetUint());
                }
            }
        }
        w.EndArray();
        doc.RemoveMember(it);
    }

    if (!(accSptr->sys() & protect::kAllPms)) { // 非全角色帐号，本帐号需要加入此角色, 先存储当前角色列表, 数据库线程加入新ID后重新写入数据库
        p->thisUpdateDatabase = true;
        p->thisCurrentRoleIds.reserve(accSptr->role().size());

        for (auto& itr : accSptr->role()) { // 存储当前角色ID列表
            p->thisCurrentRoleIds.push_back(itr->id());
        }
    }

    
    //p->req = std::move(req);
    p->accSptr = accSptr;

    // 任务线程函数, 处理数据库
    auto funcDb = [p = std::move(p)] () mutable {
        char buf[4096], tmp1[200], tmp3[400];
        auto& accSptr = p->accSptr;

        int len = sprintf(buf, "insert into `%s` (`name`,`createAccount`,`describe`,`pms`) values('%s','%s','%s','%s');",
                    Main::kTableNameRole,
                    ct::StringUtil::encodeSqlPtr(p->name.c_str(), tmp1),
                    accSptr->name().c_str(),
                    ct::StringUtil::encodeSqlPtr(p->describe.c_str(), tmp3),
                    p->pmsStr.c_str());

        auto db = Main::dbpool->grab();
        mysqlpp::Transaction trans(*db); // 事务，可能需要更新帐号下权限列表，两条sql
        auto query = db->query();
        auto res = query.execute(buf, len);

        ct::Out::debug("sql:%s, rows:%d, insert_id:%d, info:%s.\n", buf, (int)res.rows(), (int)res.insert_id(), res.info());

        if (!res || res.rows() != 1) {
            ct::Out::flag(kErr, "Error --> Create role, err(%d)(%s), sql(%s).\n", 
                          query.errnum(), query.error(), buf);
            // 回复错误，1062为重复主键错误，表示重名了
            return Main::post([p = std::move(p), err = query.errnum() == 1062 ? pub::err::kExist : pub::err::kInternal] { 
                p->api->sendHead(err); 
            });
        }

        p->newId = (uint32_t)res.insert_id();

        if (p->thisUpdateDatabase) { // 非全角色帐号，本帐号需要加入此角色，更新数据库此帐号
            int ret, len = sprintf(buf, "update `%s` set `role`='[", Main::kTableNameAccount);

            for (auto& itr : p->thisCurrentRoleIds) { // 之前的角色
                ret = sprintf(buf+len, "%u,", itr);
                len += ret;
            }

            ret = sprintf(buf+len, "%u]' where `account`='%s';", p->newId, accSptr->name().c_str()); // 加上本次的新建的角色ID
            len += ret;
            auto res = query.execute(buf, len);

            if (!res || res.rows() != 1) {
                ct::Out::flag(kErr, "Error --> Update account role, err(%d)(%s), sql(%s).\n",
                              query.errnum(), query.error(), buf);
                return Main::post([p = std::move(p)] { p->api->sendHead(pub::err::kInternal); });
            }
            ct::Out::debug("sql:%s, rows:%d, info:%s.\n", buf, (int)res.rows(), res.info());
        }

        trans.commit(); // 执行到此没失败，提交数据库事务

        // 推送到主线程执行函数，处理节点缓存
        auto funcMain = [p = std::move(p)] {
            auto& accSptr = p->accSptr;
            auto& api= p->api;
            auto roleNode = new Role(p->newId, 0, std::move(p->name), nullptr);
            roleNode->pms() = std::move(p->pms); // 更新权限列表

            // 当前帐号非全角色帐号, 此帐号节点需要加入此角色
            if (p->thisUpdateDatabase) {
                accSptr->roleAdd(roleNode);
            }

            // 日志
            pub::PbOpt pb;
            pb.set_account(accSptr->name());
            pb.set_time((uint32_t)time(nullptr));
            pb.set_opt(api->opt());
            std::string remark("(name:" + roleNode->name() + ")");
            if (!p->describe.empty()) {
                remark += "(desc:" + p->describe + ")";
            }
            pb.set_remark(remark);
            pb.set_team(accSptr->team());
            pb.set_target_id(roleNode->id());
            Main::sendLog(pb, pub::log::kOpt);

            // 回复请求
            api->sendHead(pub::err::kSuccess);
        };

        return Main::post(std::move(funcMain)); // 推送到主线程处理后续（节点缓存，全局列表等）
    };

    // 新线程中处理数据库操作
    Main::tpool->push(std::move(funcDb)); // 线程池中处理
}

void ApiHandle::roleUpdate(uptr_t&& uptr) {
    rapidjson::Document::MemberIterator it;

    // token与权限
    if ((it = doc.FindMember("token")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Role update, token.\n");
        return sendHead(pub::err::kParams);
    }
    uint64_t token = it->value.GetUint64();
    doc.RemoveMember(it);
    
    auto tokenOpt = Token::find(token);
    if (!tokenOpt) {
        return sendHead(pub::err::kToken);
    }
    auto& accSptr = (*tokenOpt)->accountSptr();
    if (!accSptr->pmsExist(Main::kPmsNameRoleWrite)) {
        return sendHead(pub::err::kPermission);
    }

    struct Info : public InfoBase {
        using InfoBase::InfoBase;
        enum Flag : uint32_t { NAME = 1, DESCRIBE = 2, PMS = 4, };
        bool hasFlag(Flag f) const { return (flag & (uint32_t)f) == (uint32_t)f; }
        void setFlag(Flag f) { this->flag |= (uint32_t)f; }
        Account::sptr_t accSptr;
        string_t name, describe;
        ct::StdString pmsStr; // 权限列表字符串形式, 用于修改数据库
        pms_list_t pms; // 权限列表map，用于更新缓存
        uint32_t flag { 0 };
        uint32_t targetId; // 操作ID
    };

    auto p = std::make_unique<Info>(std::forward<uptr_t>(uptr));

    // Step: 校验目标
    if ((it = doc.FindMember("id")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) { // 目标id
        ct::Out::debug("Error --> Role update, id.\n");
        return sendHead(pub::err::kParams);
    }
    p->targetId = it->value.GetUint();
    auto roleNode = Role::find(p->targetId);
    if (!roleNode) {
        return sendHead(pub::err::kNotFound);
    }
    if (roleNode->sys() & protect::kNoMod) { // 是否不可修改
        ct::Out::debug("Error --> Role update, protected.\n");
        return sendHead(pub::err::kPermission);
    }

    // 要修改的参数
    size_t len;
    if ((it = doc.FindMember("name")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kStringType) {
        if ((len = it->value.GetStringLength()) > Role::kNameMaxLen || len < 1) {
            ct::Out::debug("Error --> Role update, name len.\n");
            return sendHead(pub::err::kParams);
        }
        if (roleNode->name() != it->value.GetString()) { // 不相同
            p->setFlag(Info::NAME);
            p->name.assign(it->value.GetString(), len);
        }
        doc.RemoveMember(it);
    }

    if ((it = doc.FindMember("describe")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kStringType) {
        if (it->value.GetStringLength() > Role::kDescMaxLen) {
            ct::Out::debug("Error --> Permission update, describe len.\n");
            return sendHead(pub::err::kParams);
        }
        p->setFlag(Info::DESCRIBE);
        p->describe.assign(it->value.GetString(), it->value.GetStringLength());
        doc.RemoveMember(it);
    }

    if ((it = doc.FindMember("pms")) != doc.MemberEnd() && it->value.GetType() == rapidjson::kArrayType) {
        auto arr = it->value.GetArray();
        rapidjson::Writer<ct::StdString> w(p->pmsStr);
        w.StartArray();

        p->pms = roleNode->pms(); // 复制一份目标角色当前权限列表

        // 移除当前帐号拥有的权限列表
        for (auto it = p->pms.begin(); it != p->pms.end();) {
            if (accSptr->pmsExistProtect(*it)) { // 当前帐号有此权限先从map移除, 下面要根据提交的列表加
                p->pms.erase(it++);
            } else { // 当前帐号没有的权限不允许操作, 原样写入数据库列表中, 加到字符串中
                w.Uint((*it)->id());
                ++it;
            }
        }

        // 逐个校验提交的权限列表
        pms_t pmsNode;
        uint32_t pmsId;

        for (auto& itr : arr) { // 验证每个权限当前帐号是否有,有的用map存储下来,并记下字符串形式方便写db, 后续DB操作后直接替换缓存
            if (itr.GetType() != rapidjson::kNumberType) {
                continue;
            }
            pmsId = itr.GetUint();
            pmsNode = Permission::find(pmsId); // 全局权限列表是否有此权限
            if (!pmsNode) {
                continue;
            }

            // 当前帐号是否有此权限, 有则加入
            if (accSptr->pmsExistProtect(pmsNode)) { // 当前帐号有
                if (p->pms.insert(pmsNode).second) { // 再次加入列表中, set能防止重复ID, 成功才加入json串
                    w.Uint(pmsId);
                }
            }
        }

        w.EndArray();
        p->setFlag(Info::PMS);
    }

    if (!p->flag) { // 一个参数也没改
        ct::Out::debug("Error --> Role update, modify 0.\n");
        return sendHead(pub::err::kSuccess);
    }

    p->accSptr = accSptr;

    // 数据库操作函数(任务线程)
    auto funcDb = [p = std::move(p)] () mutable {
        char buf[1024], tmp[400];
        int ret, len = sprintf(buf, "update `%s` set ", Main::kTableNameRole);

        if (p->hasFlag(Info::NAME)) { // name
            ret = sprintf(buf+len, "`name`='%s',", ct::StringUtil::encodeSqlPtr(p->name.c_str(), tmp));
            len += ret;
        }

        if (p->hasFlag(Info::DESCRIBE)) { // describe
            ret = sprintf(buf + len, "`describe`='%s',", ct::StringUtil::encodeSqlPtr(p->describe.c_str(), tmp));
            len += ret;
        }

        if (p->hasFlag(Info::PMS)) {
            ret = sprintf(buf + len, "`pms`='%s',", p->pmsStr.c_str());
            len += ret;
        }

        ret = sprintf(buf+len, "`updateTime`=now() where `id`=%u;", p->targetId);
        len += ret;

        auto db = Main::dbpool->grab();
        auto query = db->query();
        auto res = query.execute(buf, len);

        ct::Out::debug("sql:%s, rows:%d.\n", buf, (int)res.rows());

        if (!res || res.rows() != 1) {
            ct::Out::flag(kErr, "Error --> Update pms, err(%d)(%s), sql(%s).\n",
                          query.errnum(), query.error(), buf);
            return Main::post([p = std::move(p), 
                              err = query.errnum() == 1062 ? pub::err::kExist : pub::err::kNotFound] { 
                p->api->sendHead(err); 
            });
        }

        // 节点缓存操作函数(主线程)
        auto funcMain = [p = std::move(p)] {
            auto& api= p->api;
            auto& accSptr = p->accSptr;
            auto roleNode = Role::find(p->targetId);
            
            if (roleNode) { // 再次查找,可能DB操作时被删除
                std::string remark;
                remark.reserve(400);

                if (p->hasFlag(Info::NAME)) { // 构造日志备注信息并更新缓存
                    remark += "(name:" + p->name + ")";
                    roleNode->name(std::move(p->name));
                }
                if (p->hasFlag(Info::PMS)) {
                    remark += "(permission:" + (std::string)p->pmsStr + ")";
                    roleNode->pms() = std::move(p->pms); // 更新权限缓存,直接替换
                }
                if (p->hasFlag(Info::DESCRIBE)) {
                    remark += "(desc:" + p->describe + ")";
                }

                // 日志
                pub::PbOpt pb;
                pb.set_account(accSptr->name());
                pb.set_time((uint32_t)time(nullptr));
                pb.set_opt(api->opt());
                pb.set_remark(remark);
                pb.set_team(accSptr->team());
                pb.set_target_id(roleNode->id());
                Main::sendLog(pb, pub::log::kOpt);
            }

            // 回复
            api->sendHead(pub::err::kSuccess);
        };

        Main::post(std::move(funcMain)); // 推送回主线程处理节点并回复
    };

    Main::tpool->push(std::move(funcDb)); // 推送到任务线程处理
}

void ApiHandle::roleDelete(uptr_t&& uptr) {
    rapidjson::Document::MemberIterator it;

    // Step: 必要参数
    if ((it = doc.FindMember("token")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) {
        ct::Out::debug("Error --> Role delete, token.\n");
        return sendHead(pub::err::kParams);
    }
    uint64_t token = it->value.GetUint64();
    doc.RemoveMember(it);

    if ((it = doc.FindMember("id")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kNumberType) { // 目标id
        ct::Out::debug("Error --> Role delete, id.\n");
        return sendHead(pub::err::kParams);
    }

    // Step: 校验权限
    auto tokenOpt = Token::find(token);
    if (!tokenOpt) {
        return sendHead(pub::err::kToken);
    }
    auto& accSptr = (*tokenOpt)->accountSptr();

    if (!accSptr->pmsExist(Main::kPmsNameRoleWrite)) {
        return sendHead(pub::err::kPermission);
    }

    // 检查目标是否存在或保护
    uint32_t id = it->value.GetUint();
    auto role = Role::find(id);

    if (!role) {
        return sendHead(pub::err::kNotFound);
    }

    if (role->sys() & protect::kNoDel) {
        return sendHead(pub::err::kPermission);
    }

    struct Info : public InfoBase {
        using InfoBase::InfoBase;
        Account::sptr_t accSptr;
        uint32_t targetId;
    };

    auto p = std::make_unique<Info>(std::forward<uptr_t>(uptr));
    p->accSptr = accSptr;
    p->targetId = id;

    // 数据库操作函数(任务线程)
    auto funcDb = [p = std::move(p)] () mutable {
        char buf[1024];
        int len = sprintf(buf, "delete from `%s` where `id`=%u and !(`sys` & %hhu);", 
                          Main::kTableNameRole, p->targetId, protect::kNoDel);

        auto db = Main::dbpool->grab();
        auto query = db->query();
        auto res = query.execute(buf, len);
        ct::Out::debug("sql:%s, rows:%d.\n", buf, (int)res.rows());

        if (!res || res.rows() != 1) {
            ct::Out::flag(kErr, "Error --> Delete role, err(%d)(%s), sql(%s).\n",
                          query.errnum(), query.error(), buf);
            return Main::post([p = std::move(p)] { p->api->sendHead(pub::err::kNotFound); });
        }

        // 节点缓存操作函数(主线程)
        auto funcMain = [p = std::move(p)] {
            auto& api= p->api;
            auto roleNode = Role::find(p->targetId);
            if (roleNode) {
                auto& accSptr = p->accSptr;

                // 日志
                pub::PbOpt pb;
                pb.set_account(accSptr->name());
                pb.set_time((uint32_t)time(nullptr));
                pb.set_opt(api->opt());
                pb.set_team(accSptr->team());
                pb.set_target_id(roleNode->id());
                Main::sendLog(pb, pub::log::kOpt);

                delete roleNode;
            }

            api->sendHead(pub::err::kSuccess); // 回复
        };

        Main::post(std::move(funcMain)); // 推送回主线程处理节点并回复
    };

    Main::tpool->push(std::move(funcDb)); // 推送到任务线程处理
}

void ApiHandle::roleIdNames(uptr_t&& uptr) {
    rapidjson::Document::MemberIterator it;

    // Step: 必要参数校验
    if ((it = doc.FindMember("id")) == doc.MemberEnd() || it->value.GetType() != rapidjson::kArrayType) {
        ct::Out::debug("Error --> role id names, ids.\n");
        return sendHead(pub::err::kParams);
    }

    auto arr = it->value.GetArray();
    setHead((uint8_t)pub::err::kSuccess); // 协议头
    rapidjson::Writer<buffer_t> w(buf);

    w.StartArray();
    uint32_t id;
    role_t roleNode;

    for (auto& itr : arr) {
        if (itr.GetType() != rapidjson::kNumberType) {
            continue;
        }

        id = (uint32_t)itr.GetInt64();
        roleNode = Role::find(id);

        if (roleNode) {
            w.StartObject();
            w.Key("id");
            w.Uint(id);
            w.Key("name");
            w.String(roleNode->name().data(), (rapidjson::SizeType)roleNode->name().size());
            w.EndObject();
        }
    }

    w.EndArray();
    session->sendReponse(std::move(buf));
}